#include "team_mdle.h"
#include "ui_team_mdle.h"
#include <QFileDialog>
#include <QDir>
#include <QTextStream>
#include <QTextCodec>
#include <QRegularExpression>
#include <QAbstractItemView>
#include <QDebug>
#include <QThread>
#include <QShortcut>
#include <QTableWidgetItem>
#include <QPlainTextEdit>
#include <QClipboard>
#include <QMenu>
#include <QMouseEvent>
#include <QMessageBox>
#include <QScrollBar>
#include <QDateTime>
#include <QImage>
#include <QFileInfo>
#include <QKeyEvent>
#include <QPixmap>
#include <QApplication>
team_mdle::team_mdle(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::team_mdle)
{
    ui->setupUi(this);
    // init all GUI
    // ---------------------------------------------
    // 配置参数
    n_row_max = NB_ROW_MAX;
    // --------------------------------------------
    // read file
    QString setting_ini = QApplication::applicationDirPath() + "setting.ini";
    settings = new QSettings(setting_ini,QSettings::IniFormat);
    QString team_name_saved = settings->value("team_name_saved","VE").toString();
    ui->ui_team_name->setText(team_name_saved);
    ui->ui_lin_cut1->setText("<!-- cut -->");
    ui->ui_lin_cut2->setText("<!-- cut -->");
    ui->ui_rad_cut1->setEnabled(false);
    ui->ui_rad_cut2->setEnabled(false);

    QList<QByteArray> codecs = QTextCodec::availableCodecs();
    ui->ui_box_codec->clear();
    foreach (const QByteArray &codec, codecs) {
        QString s_codec = QString(codec);
        ui->ui_box_codec->addItem(s_codec);
    }
    b_load_flg = 0;
    // --------------------------------------------
    // load title
    tocModelHead = new QStandardItemModel(this);
    tocModelBody = new QStandardItemModel(this);
    tocModelFoot = new QStandardItemModel(this);
    // 创建 QStandardItemModel
    tocModelAnalysis = new QStandardItemModel(0, 1, this);
    tocModelFootTxt = new  QStandardItemModel(0, 3, this);

    ui->ui_tree_head->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->ui_tree_body->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->ui_tree_foot->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->ui_tree_analysis->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->ui_tree_foot_txt->setEditTriggers(QAbstractItemView::NoEditTriggers);

    for(int i = 0; i < n_row_max; i++)
    {
        title_index[0][i] = 1;
        title_index[1][i] = 1;
        title_index[2][i] = 1;
    }
    // --------------------------------------------
    // set editor
    ui->ui_txt_head->setTabStopDistance(4 * ui->ui_txt_head->fontMetrics().averageCharWidth());
    ui->ui_txt_body->setTabStopDistance(4 * ui->ui_txt_body->fontMetrics().averageCharWidth());
    ui->ui_txt_foot->setTabStopDistance(4 * ui->ui_txt_foot->fontMetrics().averageCharWidth());
    highlight_md0 = new MarkdownHighlighter(ui->ui_txt_head->document());
    highlight_md1 = new MarkdownHighlighter(ui->ui_txt_body->document());
    highlight_md2 = new MarkdownHighlighter(ui->ui_txt_foot->document());
    //bottom
    QShortcut* shortcut = new QShortcut(Qt::CTRL + Qt::Key_S, this);
    QObject::connect(shortcut, &QShortcut::activated, ui->ui_btm_save, &QPushButton::click);
    //拓展粘贴功能
    ui->ui_txt_head->installEventFilter(this);
    ui->ui_txt_body->installEventFilter(this);
    ui->ui_txt_foot->installEventFilter(this);
    //time span
    cur_time = QDateTime::currentDateTime();
    lst_time = QDateTime::currentDateTime();
    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &team_mdle::on_ui_btm_save_clicked);
    //ui->ui_chk_auto_save->setChecked("true"); // default auto save mode
    // --------------------------------------------
    // add table show connection
    int row = n_row_max;
    int column = 2;
    table_head = new QTableWidget(row,column,this);
    table_body = new QTableWidget(row,column,this);
    table_foot = new QTableWidget(row,column,this);
    table_serach = new QTableWidget(row,3,this);
    lab_preivew  = new QLabel;
    lab_preivew ->setAlignment(Qt::AlignCenter);

    ui->ui_box_page->addTab(table_head,"head");
    ui->ui_box_page->addTab(table_body,"body");
    ui->ui_box_page->addTab(table_foot,"foot");
    ui->ui_box_page->addTab(table_serach,"search");
    ui->ui_box_page->addTab(lab_preivew,"preview");

    //add table head
    QStringList head_lab_state;
    head_lab_state << "title" << "text";
    table_head->setHorizontalHeaderLabels(head_lab_state);
    table_body->setHorizontalHeaderLabels(head_lab_state);
    table_foot->setHorizontalHeaderLabels(head_lab_state);
    //搜索结果显示
    QStringList head_lab_serach;
    head_lab_serach << "所属文件" << "所属行号" << "行信息";
    table_serach->setHorizontalHeaderLabels(head_lab_serach);
    connect(table_serach, &QTableWidget::cellDoubleClicked, this, &team_mdle::on_table_serach_double_click);
    QStringList column_lab_state;
    for(int i = 0; i < row ; i=i+1)
    {
        column_lab_state << QString::number(i);
        table_head->setVerticalHeaderLabels(column_lab_state);
        table_body->setVerticalHeaderLabels(column_lab_state);
        table_foot->setVerticalHeaderLabels(column_lab_state);
        table_serach->setVerticalHeaderLabels(column_lab_state);
    }
    // --------------------------------------------
    // table_state auto size
    table_head->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    // table->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    table_head->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
    table_head->resizeColumnsToContents();
    table_head->resizeRowsToContents();
    table_head->setEditTriggers(QAbstractItemView::NoEditTriggers);
    //body
    table_body->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    // table->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    table_body->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
    table_body->resizeColumnsToContents();
    table_body->resizeRowsToContents();
    //table_body->setEditTriggers(QAbstractItemView::NoEditTriggers);
    //foot
    table_foot->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    // table->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    table_foot->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
    table_foot->resizeColumnsToContents();
    table_foot->resizeRowsToContents();
    //table_foot->setEditTriggers(QAbstractItemView::NoEditTriggers);
    //serach
    table_serach->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    table_serach->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    table_serach->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
    table_serach->resizeColumnsToContents();
    table_serach->resizeRowsToContents();
    table_serach->setEditTriggers(QAbstractItemView::NoEditTriggers);
    // --------------------------------------------
    // 增加一些提示控件
    ui->ui_line_status->setEnabled(false);
    //增加右键菜单
    ui->ui_tree_analysis->setContextMenuPolicy(Qt::CustomContextMenu);
    ui->ui_tree_foot_txt->setContextMenuPolicy(Qt::CustomContextMenu);
    ui->ui_tree_body->setContextMenuPolicy(Qt::CustomContextMenu);
    // --------------------------------------------
    // 搜索框实现
    search_scroll_site = 0;

}

bool team_mdle::eventFilter(QObject *obj, QEvent *event) {
        if (event->type() == QEvent::KeyPress) {
            QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
            if (keyEvent->matches(QKeySequence::Paste)) {
                QString text = saveImageFromClipboardToFile();
                // 自定义处理粘贴内容
                QTextEdit *textEdit = qobject_cast<QTextEdit*>(obj);
                if (textEdit) {
                    textEdit->insertPlainText(text);
                    return true;
                }
            }
        }
        return QObject::eventFilter(obj, event);
    }

team_mdle::~team_mdle()
{
    delete ui;
}

void team_mdle::update_file_path(QList<QString> l_file)
{
    // read path from file_mdle
    QString p_team = l_file[P_TEAM_MDLE];
    ui->ui_line_work_dir->setText(p_team);
    lst_box_part = 0; //第一次初始化的值
    on_ui_btm_load_clicked();
}

void team_mdle::on_ui_btm_update_dir_clicked()
{
    QString p_dir  = QFileDialog::getExistingDirectory
                            (this,
                             "Please choose an work dir",
                             "");
    if (p_dir.isEmpty())
    {
        qDebug() << "你取消了选择。";
        return;
    }
    ui->ui_line_work_dir->setText(p_dir);
    ui->ui_box_part->clear();
    ui->ui_box_part->addItem("");
    on_ui_btm_load_clicked();
}


void team_mdle::on_ui_btm_load_clicked()
{
    QStringList filters;
    QString team_name = ui->ui_team_name->text() + "*.md";
    filters << team_name;
    QDir dir(ui->ui_line_work_dir->text());
    if (!dir.exists())
    {
        qDebug() << "目录不存在: " << dir;
        return;
    }
    dir.setNameFilters(filters);
    QStringList fileList = dir.entryList(QDir::Files);
    if(b_load_flg == 1)
    {
        lst_box_part = ui->ui_box_part->currentIndex(); //new chose
        //qDebug() << lst_box_part;
    }
    ui->ui_box_part->clear();
    foreach(const QString &file , fileList)
    {
        ui->ui_box_part->addItem(file);
    }
    b_load_flg = 1;
    ui->ui_box_part->setCurrentIndex(lst_box_part);
    //加载完成后立刻对数据进行解析
    on_ui_btm_analysis_clicked();
    //更新项目名
    settings->setValue("team_name_saved",ui->ui_team_name->text());
}


void team_mdle::on_ui_box_part_currentIndexChanged(const QString &arg1)
{

    if (arg1.isEmpty())
    {
        return;
    }
    //切换到编辑搜索界面以加快加载的速度
    ui->ui_box_page->setCurrentIndex(3);
    //read file three part
    QString pns_file = ui->ui_line_work_dir->text() + arg1; // get read file
    QFile file(pns_file);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QString s_err = file.errorString() + ":" + pns_file;
        char * err_info = s_err.toUtf8().data();
        qWarning("Failed to open read index file %s ",err_info);
        return;
    }
    ui->ui_txt_head->clear();
    ui->ui_txt_body->clear();
    ui->ui_txt_foot->clear();
    //read file to edit
    QTextStream in(&file);
    QString s_codec = ui->ui_box_codec->currentText();
    in.setCodec(QTextCodec::codecForName(s_codec.toUtf8())); // default code
    int n_cur_part = 0;
    int title_cnt = 0;
    int line_cnt = 1;
    //clear table
    table_head->clearContents();
    table_body->clearContents();
    table_foot->clearContents();

    //重新判断
    ui->ui_rad_cut1->setChecked(false);
    ui->ui_rad_cut2->setChecked(false);
    ui->ui_rad_cut1->setStyleSheet("background-color: red");
    ui->ui_rad_cut2->setStyleSheet("background-color: red");

    //update data
    QString s_title_data;
    s_title_data.clear();
    while (!in.atEnd()) {
        QString line = in.readLine();

        if( ( line.contains(ui->ui_lin_cut1->text())
            ||line.contains(ui->ui_lin_cut2->text()) )
        && n_cur_part < 2 //限制最大的识别数
                )
        {
            if (n_cur_part == 0)
            {
                ui->ui_rad_cut1->setChecked(true);
                ui->ui_rad_cut1->setStyleSheet("background-color: green");
            }
            if (n_cur_part == 1)
            {
                ui->ui_rad_cut2->setChecked(true);
                ui->ui_rad_cut2->setStyleSheet("background-color: green");
            }
            n_cur_part ++;
            line_cnt  = 0;
            title_cnt = 0;
            continue; //not consider cut data
        }
        else
        {
            switch(n_cur_part)
            {
            case 0: ui->ui_txt_head->append(line); break;
            case 1: ui->ui_txt_body->append(line); break;
            case 2: ui->ui_txt_foot->append(line); break;
            default: break;
            }
        }

        if(n_cur_part < 3) //max part is 3
        {
            //update title
            QRegularExpression headingRegex("^(#{1,6})\\s+(.*)$", QRegularExpression::MultilineOption);
            QRegularExpressionMatchIterator matchIterator = headingRegex.globalMatch(line);

            if(matchIterator.hasNext()) //match succeed
            {
                title_cnt++;
                title_index[n_cur_part][title_cnt] = line_cnt;

                QTableWidgetItem *item_title = new QTableWidgetItem;
                item_title->setText(line);
                switch(n_cur_part)
                {
                case 0: {
                    table_head->setItem(title_cnt,0,item_title); //next title
                    break;
                }
                case 1: {
                    table_body->setItem(title_cnt,0,item_title); //next title
                    break;
                }
                case 2: {
                    table_foot->setItem(title_cnt,0,item_title); //next title
                    break;
                }
                default: break;
                }

                //qDebug() << s_title_data << line << title_cnt << line_cnt;
                s_title_data.clear();
                if(title_cnt >= n_row_max - 1)
                {
                    file.close();
                    return;
                }

                //qDebug() << "line1" << n_cur_part << "time" << QDateTime::currentDateTime();
            }
            else
            {
                s_title_data += line + "\n";
                QTableWidgetItem *item_data  = new QTableWidgetItem;
                item_data->setText(s_title_data);
                switch(n_cur_part)
                {
                case 0: {
                    table_head->setItem(title_cnt,1,item_data); //current data
                    break;
                }
                case 1: {
                    table_body->setItem(title_cnt,1,item_data); //current data
                    break;
                }
                case 2: {
                    table_foot->setItem(title_cnt,1,item_data); //current data
                    break;
                }
                default: break;
                }
                //qDebug() << "line2" << n_cur_part << "time" << QDateTime::currentDateTime();
            }

            line_cnt++;
            //
        }
        //qDebug() << "line" << n_cur_part << "time" << QDateTime::currentDateTime();
        ui->ui_prc_analysis->setValue(line_cnt%100);
    }
    ui->ui_prc_analysis->setValue(100);
    file.close();
    QThread::msleep(1);
}


void team_mdle::get_markdown_title_tree(QStandardItemModel * tocModel,QString markdownText, int part_txt)
{
    QRegularExpression headingRegex("^(#{1,6})\\s+(.*)$", QRegularExpression::MultilineOption);
    QRegularExpressionMatchIterator matchIterator = headingRegex.globalMatch(markdownText);

    QList<QStandardItem*> parentItems;
    parentItems.append(nullptr);
    int title_cnt = 0;
    while (matchIterator.hasNext())
    {
        QRegularExpressionMatch match = matchIterator.next();
        QString title = match.captured(2);
        int level = match.captured(1).length();

        // get parrent items
        while (parentItems.size() > level) {
            parentItems.removeLast();
        }
        while (parentItems.size() < level) {
            parentItems.append(nullptr);
        }

        QStandardItem *parent = parentItems[level - 1];
        QString itemText = QString("%1 --%2").arg(title).arg(title_index[part_txt][title_cnt]);
        QStandardItem *item = new QStandardItem(itemText);

        if (parent) {
            parent->appendRow(item);
        } else {
            tocModel->appendRow(item);
        }

        // update parrent items
        if (parentItems.size() == level) {
            parentItems.append(item);
        } else {
            parentItems[level] = item;
        }
        title_cnt ++;
    }
}
void team_mdle::on_ui_txt_head_textChanged()
{

    ui->ui_tree_head->setModel(tocModelHead);
    //get list of title
    tocModelHead->clear();
    tocModelHead->setHorizontalHeaderLabels({"项目信息"});
    //get title
    QString markdownText = ui->ui_txt_head->toPlainText();
    get_markdown_title_tree(tocModelHead,markdownText,0);
    ui->ui_btm_save->setStyleSheet("background-color: yellow");
    ui->ui_tree_head->expandAll();

}

void team_mdle::on_ui_txt_body_textChanged()
{
    ui->ui_tree_body->setModel(tocModelBody);
    //get list of title
    tocModelBody->clear();
    tocModelBody->setHorizontalHeaderLabels({"项目内容"});
    //get title
    QString markdownText = ui->ui_txt_body->toPlainText();
    get_markdown_title_tree(tocModelBody,markdownText,1);
    ui->ui_btm_save->setStyleSheet("background-color: yellow");
    ui->ui_tree_body->expandAll();
}


void team_mdle::on_ui_txt_foot_textChanged()
{
    ui->ui_tree_foot->setModel(tocModelFoot);
    //get list of title
    tocModelFoot->clear();
    tocModelFoot->setHorizontalHeaderLabels({"项目关联"});
    //get title
    QString markdownText = ui->ui_txt_foot->toPlainText();
    get_markdown_title_tree(tocModelFoot,markdownText,2);
    // --------------------------------------------
    // set file state
    ui->ui_btm_save->setStyleSheet("background-color: yellow");
    ui->ui_tree_foot->expandAll();

}
void team_mdle::jumpToLine(QTextEdit *textEdit, int lineNumber) {
    if (lineNumber < 1) {
        return;
    }
    // get text cursor
    QTextCursor cursor = textEdit->textCursor();
    // move to head
    cursor.movePosition(QTextCursor::Start);
    // move to aim line
    for (int i = 1; i < lineNumber; ++i) {
        cursor.movePosition(QTextCursor::Down);
    }
    // set new cursor
    textEdit->setTextCursor(cursor);
    // set view to new line
    textEdit->ensureCursorVisible();
}



void team_mdle::on_ui_tree_head_doubleClicked(const QModelIndex &index)
{
    // --------------------------------------------
    // jump to title line
    QString node;
    if(index.isValid())
    {
        node = tocModelHead->data(index).toString();
    }
    QStringList parts = node.split("--");
    QString line_id = "1";
    if (parts.size() > 1)
    {
         line_id = parts.at(1);
    }
    int line = line_id.toInt();
    jumpToLine(ui->ui_txt_head,line);

}


void team_mdle::on_ui_tree_body_doubleClicked(const QModelIndex &index)
{
    QString node;
    if(index.isValid())
    {
        node = tocModelBody->data(index).toString();
    }

    QStringList parts = node.split("--");
    QString line_id = "1";
    if (parts.size() > 1)
    {
         line_id = parts.at(1);
    }
    int line = line_id.toInt();
    jumpToLine(ui->ui_txt_body,line);
    //qDebug() << node << line_id << line;
}


void team_mdle::on_ui_tree_foot_doubleClicked(const QModelIndex &index)
{
    QString node;
    if(index.isValid())
    {
        node = tocModelFoot->data(index).toString();
    }
    QStringList parts = node.split("--");
    QString line_id = "1";
    if (parts.size() > 1)
    {
         line_id = parts.at(1);
    }
    int line = line_id.toInt();
    jumpToLine(ui->ui_txt_foot,line);
}


void team_mdle::on_ui_btm_close_clicked()
{
    this->close();
}


void team_mdle::on_ui_btm_save_clicked()
{
    //detect write span
    cur_time = QDateTime::currentDateTime();
    if(lst_time.msecsTo(cur_time) < 10) //update is too fast
    {
        return;
    }
    else //update ok and rem it as follow condition
    {
        lst_time = QDateTime::currentDateTime();
    }
    //write file three part
    QString pns_file = ui->ui_line_work_dir->text() + "/" + ui->ui_box_part->currentText(); // get read file
    QFile file(pns_file);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        char * err_info = file.errorString().toUtf8().data();
        qWarning("Failed to open write file %s",err_info);
        return;
    }

    QString data_file =     ui->ui_txt_head->toPlainText() + "\n"
                         +  ui->ui_lin_cut1->text() + "\n"
                         +  ui->ui_txt_body->toPlainText() + "\n"
                         +  ui->ui_lin_cut2->text() + "\n"
                         +  ui->ui_txt_foot->toPlainText() + "\n";
    QTextStream out(&file);
    QString s_codec = ui->ui_box_codec->currentText();
    out.setCodec(s_codec.toUtf8());
    out << data_file;
    QThread::msleep(1);
    file.close();
    //qDebug() << data_file;
    ui->ui_btm_save->setStyleSheet("background-color: green");
}


void team_mdle::on_ui_chk_auto_save_stateChanged(int arg1)
{
    if(arg1) //checked
    {
        timer->start(5000);
    }
    else
    {
        timer->stop();
    }
}


void team_mdle::on_ui_btm_analysis_clicked()
{
    // --------------------------------------------
    // 文件导航
    // 设置模型到 QTreeView
    tocModelAnalysis->clear();
    tocModelAnalysis->setHorizontalHeaderLabels({"文件导航"});
    ui->ui_tree_analysis->setModel(tocModelAnalysis);
    // 添加父节点
    QList<QStandardItem *>parentItem_list;
    parentItem_list.clear();
    for (int i = 0; i < ui->ui_box_part->count();i++)
    {
        QStandardItem * parentItem1 = new QStandardItem(ui->ui_box_part->itemText(i)); //以第一个文件为父节点
        parentItem_list.append(parentItem1);
    }
    tocModelAnalysis->appendRow(parentItem_list[0]);
    tocModelAnalysis->appendRow(parentItem_list[ui->ui_box_part->count()-1]);
    // --------------------------------------------
    // 标识导航(sign)
    tocModelFootTxt->clear();
    tocModelFootTxt->setHorizontalHeaderLabels({"标识导航","行","文件","节点内容"});
    ui->ui_tree_foot_txt->setModel(tocModelFootTxt);
    QList<QList<QStandardItem *>>parentItem_sign_list;
    QList<QString> parentItem_sign_string;
    parentItem_sign_list.clear();
    parentItem_sign_string.clear();
    // 更新其他的节点
    for (int i = 0; i < ui->ui_box_part->count();i++) //load team all part
    {
        QString part_name = ui->ui_box_part->itemText(i);
        QString pns_file = ui->ui_line_work_dir->text() + "/" + part_name;
        //read other node
        QFile file(pns_file);
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
            char * err_info = file.errorString().toUtf8().data();
            qWarning("Failed to open read analysis file %s",err_info);
            return;
        }
        QTextStream in(&file);
        QString s_codec = ui->ui_box_codec->currentText();
        in.setCodec(QTextCodec::codecForName(s_codec.toUtf8())); // default code
        int n_cur_part = 0;
        int n_lin_cnt = 1;
        while (!in.atEnd()) {
            //读取文件中的各个部分
            QString line = in.readLine();
            if(line.contains(ui->ui_lin_cut1->text())
            || line.contains(ui->ui_lin_cut2->text())
                    )
            {
                n_cur_part ++;
                n_lin_cnt = 0;
            }
            if(n_cur_part == 1)
            {
                QRegularExpression headingRegex("^(#{1,6})(.*)\\{#(.*?)\\}", QRegularExpression::MultilineOption);
                QRegularExpressionMatchIterator matchIterator = headingRegex.globalMatch(line);
                while(matchIterator.hasNext()) //提前构建父节点，方便子节点加入
                {
                    //更新所有的节点
                    //qDebug() << matchIterator.next().captured(0) << matchIterator.next().captured(2) << matchIterator.next().captured(3);
                    QRegularExpressionMatch match = matchIterator.next();
                    QString s_sign_contxt  = match.captured(2);
                    QString s_sign_target  = match.captured(3);

                    QStandardItem * parentItem1 = new QStandardItem(s_sign_target);
                    QStandardItem * parentItem2 = new QStandardItem(QString::number(n_lin_cnt));
                    QStandardItem * parentItem3 = new QStandardItem(part_name);
                    QStandardItem * parentItem4 = new QStandardItem(s_sign_contxt.trimmed());

                    QList<QStandardItem *> parentItem1_sum;
                    parentItem1_sum.clear();
                    parentItem1_sum.append(parentItem1);
                    parentItem1_sum.append(parentItem2);
                    parentItem1_sum.append(parentItem3);
                    parentItem1_sum.append(parentItem4);
                    parentItem_sign_list.append(parentItem1_sum); //更新所有父节点
                    parentItem_sign_string.append(s_sign_target);
                    if(i == 0)
                    {
                        //tocModelFootTxt->appendRow(parentItem1);
                        tocModelFootTxt->appendRow(parentItem1_sum);
                        //设置列宽度
                        QHeaderView *header = ui->ui_tree_foot_txt->header();
                        for (int i = 0; i < tocModelFootTxt->columnCount(); ++i)
                        {
                            header->setSectionResizeMode(i, QHeaderView::ResizeToContents);
                        }

                    }
                    //qDebug() << "target" << s_sign_target << "list" << parentItem_sign_string;
                }

            }
            if(n_cur_part == 2) //analysis foot info
            {
                //注册所有的文件的选项卡
                for (int j = 0; j < ui->ui_box_part->count();j++) //load team all part
                {
                    QString part_name_compare = ui->ui_box_part->itemText(j);
                    if(line.contains(part_name_compare)) //find parrent node
                    {
                        // 调整相关的父节点的位置
                        parentItem_list[j]->appendRow(parentItem_list[i]); //获取所有文件的顺序
                        //qDebug() << "father" <<i << "child" << j;
                    }
                }
                //更新文件内的标识关联
                QRegularExpression headingRegex("#\\{.*?\\}", QRegularExpression::MultilineOption);
                QRegularExpressionMatchIterator matchIterator = headingRegex.globalMatch(line);
                int numb_match = 0;
                QStringList list_sign;
                list_sign.clear();
                while(matchIterator.hasNext()) //一行内存在两个匹配结果才能建立连接
                {
                    list_sign.append(matchIterator.next().captured(0));
                    numb_match++;

                }
                //qDebug() << "list_sign" << list_sign << numb_match;
                //qDebug() << "match" << list_sign << "numb" << numb_match ;
                if(numb_match == 2) //满足两个链接的关联的匹配
                {
                    for (int k = 0; k < parentItem_sign_string.size(); k++)
                    {
                        for (int m = 0; m < parentItem_sign_string.size(); m++)
                        {
                            if(list_sign[1].contains(parentItem_sign_string[k]) //寻找到子节点
                            && list_sign[0].contains(parentItem_sign_string[m]))//寻找到父节点
                            {
                                parentItem_sign_list[k][0]->appendRow(parentItem_sign_list[m]); //构建节点
                                //qDebug() << "parent2" << k << parentItem_sign_string[k] << "child" << m << parentItem_sign_string[m];
                                //qDebug() << "parent" << k  << "child" << m;
                            }

                            //qDebug() << "parent" << parentItem_sign_string[k] << "child" << parentItem_sign_string[m];
                        }
                    }

                }
            }
            n_lin_cnt++;
        } //end while(1)
        ui->ui_prc_analysis->setValue(i * 100 / ui->ui_box_part->count());
        file.close();
    }//endfor
    ui->ui_prc_analysis->setValue(100);
    //展开树状图
    ui->ui_tree_foot_txt->expandAll();
    ui->ui_tree_analysis->expandAll();

}
void team_mdle::tableUpdateByFile(QString pns_file,int target_line)
{
    QFile file(pns_file);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QString s_err = file.errorString() + ":" + pns_file;
        char * err_info = s_err.toUtf8().data();
        qWarning("Failed to open read analysis file %s ",err_info);
        return;
    }
    //read file to edit
    QTextStream in(&file);
    QString s_codec = ui->ui_box_codec->currentText();
    in.setCodec(QTextCodec::codecForName(s_codec.toUtf8())); // default code
    int n_cur_part = 0;
    int title_cnt = 0;
    int line_cnt = 1;
    //clear table
    table_head->clearContents();
    table_body->clearContents();
    table_foot->clearContents();

    //update data
    QString s_title_data;
    s_title_data.clear();
    while (!in.atEnd()) {
        QString line = in.readLine();
        if(line.contains(ui->ui_lin_cut1->text())
        || line.contains(ui->ui_lin_cut2->text())
                )
        {
            n_cur_part ++;
            line_cnt  = 0;
            title_cnt = 0;
            continue; //not consider cut data
        }
        if(n_cur_part < 3) //max part is 3
        {
            //update title
            QRegularExpression headingRegex("^(#{1,6})\\s+(.*)$", QRegularExpression::MultilineOption);
            QRegularExpressionMatchIterator matchIterator = headingRegex.globalMatch(line);

            if(matchIterator.hasNext()) //match succeed
            {
                title_index[n_cur_part][title_cnt] = line_cnt;

                QTableWidgetItem *item_title = new QTableWidgetItem;
                item_title->setText(line);

                title_cnt++; //提前更新标题，以便和当前标题下的数据对应
                switch(n_cur_part)
                {
                case 0: {
                    table_head->setItem(title_cnt,0,item_title); //next title
                    break;
                }
                case 1: {
                    table_body->setItem(title_cnt,0,item_title); //next title
                    //qDebug() << "title " << title_cnt << line;
                    if(line_cnt < target_line)
                    {

                        ui->ui_box_page->setCurrentIndex(1);
                        table_body->scrollToItem(item_title,QAbstractItemView::PositionAtCenter);
                    }
                    break;
                }
                case 2: {
                    table_foot->setItem(title_cnt,0,item_title); //next title
                    break;
                }
                default: break;
                }
                //qDebug() << "line" << line_cnt << "target" << target_line;
                //qDebug() << s_title_data << line << title_cnt << line_cnt;
                s_title_data.clear();

            }
            else
            {
                s_title_data += line + "\n";
                QTableWidgetItem *item_data  = new QTableWidgetItem;
                item_data->setText(s_title_data);
                switch(n_cur_part)
                {
                case 0: {
                    table_head->setItem(title_cnt,1,item_data); //current data
                    break;
                }
                case 1: {
                    table_body->setItem(title_cnt,1,item_data); //current data
                    //qDebug() << "data " << title_cnt << item_data;
                    break;
                }
                case 2: {
                    table_foot->setItem(title_cnt,1,item_data); //current data
                    break;
                }
                default: break;
                }
            }

            line_cnt++;
            //
        }
        ui->ui_prc_analysis->setValue(line_cnt % 100);

    }
    ui->ui_prc_analysis->setValue(100);
    file.close();
    QThread::msleep(1);
}




void team_mdle::on_ui_tree_analysis_doubleClicked(const QModelIndex &index)
{
    QString node;
    anysis_index = index;
    if(index.isValid())
    {
        node = tocModelAnalysis->data(index).toString();
    }
    QString pns_file = ui->ui_line_work_dir->text() + node; // get read file
    tableUpdateByFile(pns_file,-1);

}


void team_mdle::on_ui_tree_foot_txt_doubleClicked(const QModelIndex &index)
{
    QString s_node;
    QString s_line;
    int     i_line = 0;
    QString s_file;
    if(index.isValid())
    {
        QModelIndex index1 = tocModelFootTxt->index(index.row(), 1, index.parent());
        QModelIndex index2 = tocModelFootTxt->index(index.row(), 2, index.parent());
        s_node = tocModelFootTxt->data(index,Qt::DisplayRole).toString();
        s_line = tocModelFootTxt->data(index1,Qt::DisplayRole).toString();
        s_file = tocModelFootTxt->data(index2,Qt::DisplayRole).toString();

        i_line = s_line.toInt();
        //更新文件的内容
        QString pns_file = ui->ui_line_work_dir->text() + s_file; // get read file
        tableUpdateByFile(pns_file,i_line);
    }

}


void team_mdle::on_ui_txt_head_cursorPositionChanged()
{
    QTextCursor cursor = ui->ui_txt_head->textCursor();

   // 获取行号和列号
   int row = cursor.blockNumber() + 1; // 行号从 1 开始
   int col = cursor.columnNumber() + 1; // 列号从 1 开始

   // 更新标签文本
   ui->ui_line_status->setText(QString("[head] Row: %1, Col: %2").arg(row).arg(col));

}


void team_mdle::on_ui_txt_body_cursorPositionChanged()
{
    QTextCursor cursor = ui->ui_txt_body->textCursor();

   // 获取行号和列号
   int row = cursor.blockNumber() + 1; // 行号从 1 开始
   int col = cursor.columnNumber() + 1; // 列号从 1 开始

   // 更新标签文本
   ui->ui_line_status->setText(QString("[body] Row: %1, Col: %2").arg(row).arg(col));
}


void team_mdle::on_ui_txt_foot_cursorPositionChanged()
{
    QTextCursor cursor = ui->ui_txt_foot->textCursor();

   // 获取行号和列号
   int row = cursor.blockNumber() + 1; // 行号从 1 开始
   int col = cursor.columnNumber() + 1; // 列号从 1 开始

   // 更新标签文本
   ui->ui_line_status->setText(QString("[foot] Row: %1, Col: %2").arg(row).arg(col));
}


void team_mdle::copy_analysis_title()
{
    //读取当前的标题
    QString s_node;
    if(anysis_index.isValid())
    {
        s_node = tocModelAnalysis->data(anysis_index,Qt::DisplayRole).toString();
    }
    //复制到剪切板
    QClipboard *clipboard = QApplication::clipboard();
    // 将文本复制到剪贴板
    clipboard->setText(s_node);
    //qDebug() << "result" << s_node << "index" << anysis_index;
}
void team_mdle::on_ui_tree_analysis_clicked(const QModelIndex &index)
{
    anysis_index = index;
}
void team_mdle::on_ui_tree_foot_txt_clicked(const QModelIndex &index)
{
    foot_index = index;
}
void team_mdle::copy_analysis_link()
{
    //读取当前的标题
    QString s_node;
    if(anysis_index.isValid())
    {
        s_node = tocModelAnalysis->data(anysis_index,Qt::DisplayRole).toString();
    }
    QString link;
    link = "[](./" + s_node + "#{})";
    //复制到剪切板
    QClipboard *clipboard = QApplication::clipboard();
    // 将文本复制到剪贴板
    clipboard->setText(link);
    //qDebug() << "result" << s_node << "index" << anysis_index;
}



void team_mdle::on_ui_tree_analysis_customContextMenuRequested(const QPoint &pos)
{
    //qDebug() << pos;
    QMenu menu;
    // 获取点击位置
    QPoint globalPos = ui->ui_tree_analysis->mapToGlobal(pos);
    //添加action
    QAction *action1 = new QAction(QStringLiteral("复制名称"));
    QAction *action2 = new QAction(QStringLiteral("复制链接"));

    menu.addAction(action1);
    menu.addAction(action2);

    connect(action1,&QAction::triggered,this,&team_mdle::copy_analysis_title);
    connect(action2,&QAction::triggered,this,&team_mdle::copy_analysis_link);

    menu.exec(globalPos);
}
void team_mdle::on_ui_tree_foot_txt_customContextMenuRequested(const QPoint &pos)
{
    //qDebug() << pos;
    QMenu menu;
    // 获取点击位置
    QPoint globalPos = ui->ui_tree_foot_txt->mapToGlobal(pos);
    //添加action
    QAction *action1 = new QAction(QStringLiteral("复制终点"));

    menu.addAction(action1);

    connect(action1,&QAction::triggered,this,&team_mdle::copy_foot_node);

    menu.exec(globalPos);
}
void team_mdle::copy_foot_node()
{
    QString s_node;
    QString s_file;
    QString s_contxt;
    if(foot_index.isValid())
    {
        QModelIndex index2 = tocModelFootTxt->index(foot_index.row(), 2, foot_index.parent());
        QModelIndex index3 = tocModelFootTxt->index(foot_index.row(), 3, foot_index.parent());

        s_node   = tocModelFootTxt->data(foot_index,Qt::DisplayRole).toString();
        s_file   = tocModelFootTxt->data(index2,Qt::DisplayRole).toString();
        s_contxt = tocModelFootTxt->data(index3,Qt::DisplayRole).toString();

    }
    QString link = " | ["+ s_node +"](./" + s_file + "#{" + s_node + "}) |" + s_contxt + "| ";
    //复制到剪切板
    QClipboard *clipboard = QApplication::clipboard();
    // 将文本复制到剪贴板
    clipboard->setText(link);
    //qDebug() << "result" << s_node << "index" << anysis_index;
}




void team_mdle::on_ui_btm_serach_clicked()
{
    int serach_numb = 0;
    QString searchText = ui->ui_lin_serach->text();
    if (!searchText.isEmpty())
    {
        // 清除之前的高亮显示
        QTextCharFormat normalFormat;
        QTextCursor cursor = ui->ui_txt_body->textCursor();
        cursor.select(QTextCursor::Document);
        cursor.setCharFormat(normalFormat);

        bool found = false;
        QTextDocument *document = ui->ui_txt_body->document();
        QTextCursor highlightCursor(document);
        QTextCharFormat highlightFormat;
        highlightFormat.setBackground(Qt::yellow); // 设置高亮背景颜色为黄色


        QScrollBar *scrollBar = ui->ui_txt_body->verticalScrollBar();
        QStringList positions;

        while (!highlightCursor.isNull() && !highlightCursor.atEnd())
        {
            highlightCursor = document->find(searchText, highlightCursor);
            if (!highlightCursor.isNull()) {
                found = true;
                highlightCursor.mergeCharFormat(highlightFormat);

                // 计算搜索结果在滚动条上的位置
                double pos = (double)highlightCursor.position() / document->characterCount();
                int scrollPos = pos * scrollBar->maximum();
                positions.append(QString::number(scrollPos));
                // 设置滚动条的位置
                if(search_scroll_site == serach_numb
                || serach_numb == 0)
                {
                    scrollBar->setValue(scrollPos);
                }
                highlightCursor.setPosition(highlightCursor.position() + searchText.length());
                serach_numb ++;
            }
        }

        if (! found)
        {
            QMessageBox::information(this, "搜索结果", "未找到匹配内容。");
            scrollBar->setStyleSheet("");
        }
    }
    // 判断搜索结果的位置
    if(search_scroll_site >= serach_numb)
    {
        search_scroll_site = 0;
    }
    else
    {
        search_scroll_site ++;
    }
}





void team_mdle::on_ui_btm_search_all_clicked()
{
    QString searchText = ui->ui_lin_serach->text();
    table_serach->clearContents();
    if (!searchText.isEmpty())
    {
        int n_match_cnt = 0;
        for (int i = 0; i < ui->ui_box_part->count();i++) //load team all part
        {
            QString part_name = ui->ui_box_part->itemText(i);
            QString pns_file = ui->ui_line_work_dir->text() + "/" + part_name;
            //read other node
            QFile file(pns_file);
            if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
                char * err_info = file.errorString().toUtf8().data();
                qWarning("Failed to open read analysis file %s",err_info);
                return;
            }
            QTextStream in(&file);
            QString s_codec = ui->ui_box_codec->currentText();
            in.setCodec(QTextCodec::codecForName(s_codec.toUtf8())); // default code
            int n_lin_cnt = 0;
            while (!in.atEnd())
            {
                //读取文件中的各个部分
                QString line = in.readLine();
                if(line.contains(searchText))
                {
                    QTableWidgetItem *item_title1 = new QTableWidgetItem;
                    item_title1->setText(QString::number(n_lin_cnt));
                    table_serach->setItem(n_match_cnt,1,item_title1);
                    QTableWidgetItem *item_title2 = new QTableWidgetItem;
                    item_title2->setText(line);
                    table_serach->setItem(n_match_cnt,2,item_title2);
                    QTableWidgetItem *item_title3 = new QTableWidgetItem;
                    item_title3->setText(part_name);
                    table_serach->setItem(n_match_cnt,0,item_title3);
                    n_match_cnt++;
                    if(n_match_cnt == n_row_max - 1)
                    {
                        file.close();
                        qDebug() << "table is full";
                        return;
                    }
                }
                n_lin_cnt ++;
            }

            file.close();
            ui->ui_prc_analysis->setValue(i * 100 / ui->ui_box_part->count());
        }
        ui->ui_prc_analysis->setValue(100);
    }
    ui->ui_box_page->setCurrentIndex(3);
}

void team_mdle::on_table_serach_double_click(int row, int column)
{
    QString file;
    QString line;
    if(column < 3)
    {
       QTableWidgetItem *item1 = table_serach->item(row,0);
       if(item1)
       {
           file = item1->text();
       }
       QTableWidgetItem *item2 = table_serach->item(row,1);
       if(item2)
       {
           line = item2->text();
       }
       QString pns_file = ui->ui_line_work_dir->text() + "/" + file;
       tableUpdateByFile(pns_file,line.toInt());
    }
}


void team_mdle::on_ui_btm_replace_clicked()
{
    QString replaceText = ui->ui_lin_replace->text();
    int serach_numb = 0;
    QString searchText = ui->ui_lin_serach->text();
    if (!searchText.isEmpty())
    {
        // 清除之前的高亮显示
        QTextCharFormat normalFormat;
        QTextCursor cursor = ui->ui_txt_body->textCursor();
        cursor.select(QTextCursor::Document);
        cursor.setCharFormat(normalFormat);

        bool found = false;
        QTextDocument *document = ui->ui_txt_body->document();
        QTextCursor highlightCursor(document);

        QTextCharFormat highlightFormat;
        highlightFormat.setBackground(Qt::gray); // 设置高亮背景颜色为灰色

        QScrollBar *scrollBar = ui->ui_txt_body->verticalScrollBar();
        QStringList positions;

        while (!highlightCursor.isNull() && !highlightCursor.atEnd())
        {
            highlightCursor = document->find(searchText, highlightCursor);
            if (!highlightCursor.isNull()) {
                found = true;
                // 计算搜索结果在滚动条上的位置
                double pos = (double)highlightCursor.position() / document->characterCount();
                int scrollPos = pos * scrollBar->maximum();
                positions.append(QString::number(scrollPos));

                // 设置滚动条的位置
                if(search_scroll_site == serach_numb
                || serach_numb == 0)
                {
                    scrollBar->setValue(scrollPos);
                }
                // 替换指定的选中内容
                if(search_scroll_site == serach_numb){
                    //选择文本
                    cursor.clearSelection();
                    cursor.setPosition(highlightCursor.position() - searchText.length());
                    cursor.setPosition(highlightCursor.position() , QTextCursor::KeepAnchor);
                    //qDebug() << "替换前" << cursor.selectedText() << searchText.length();
                    //替换文本
                    cursor.insertText(replaceText);
                    //qDebug() << search_scroll_site << serach_numb;
                    ui->ui_txt_body->setTextCursor(cursor);
                }
                highlightCursor.mergeCharFormat(highlightFormat);
                highlightCursor.setPosition(highlightCursor.position() + searchText.length());
                serach_numb ++;
            }
        }
        if (! found)
        {
            QMessageBox::information(this, "替换结果", "未找到匹配内容。");
            scrollBar->setStyleSheet("");
            return;
        }
    }
    // 判断搜索结果的位置
    if(search_scroll_site >= serach_numb)
    {
        QString info = "共寻找到" + QString::number(serach_numb) + "结果";
        QMessageBox::information(this, "搜索结果", info);
        search_scroll_site = 0;
    }
    else
    {
        search_scroll_site ++;
    }
}


void team_mdle::on_ui_btm_replace_all_clicked()
{
    QTextCursor cursor = ui->ui_txt_body->textCursor();
    int pos = cursor.position();
    //替换文本
    QString searchText = ui->ui_lin_serach->text();
    QString replaceText = ui->ui_lin_replace->text();
    QString text = ui->ui_txt_body->toPlainText();
    text.replace(searchText, replaceText);
    ui->ui_txt_body->setPlainText(text);
    // 清除之前的高亮显示
    QTextCharFormat normalFormat;
    cursor.select(QTextCursor::Document);
    cursor.setCharFormat(normalFormat);
    cursor.setPosition(pos);
    ui->ui_txt_body->setTextCursor(cursor);
}


void team_mdle::on_ui_lin_serach_textChanged(const QString &arg1)
{
    if(arg1.isEmpty())
    {
        qDebug() << "serach is empty";
    }

    search_scroll_site = 0;
}

QString team_mdle::saveImageFromClipboardToFile() {
    QClipboard *clipboard = QApplication::clipboard();
    QImage image = clipboard->image();

    if (image.isNull()) {
        //qDebug() << "剪贴板中没有图片。";
        return clipboard->text();
    }

    // 生成一个唯一的文件名
    QString timestamp = QDateTime::currentDateTime().toString("yyyyMMddHHmmsszzz");
    QString imag_md  =  ui->ui_box_part->currentText(); //获取缓存目录
    QFileInfo file_info(imag_md);
    QString dir = ui->ui_line_work_dir->text() + "/" + file_info.baseName();
    QDir::setCurrent(dir);
    QString filePath = QString("image_%1.png").arg(timestamp);
    QString imag_link = "![image](./" + file_info.baseName() + "/" + filePath + ")";
    qDebug() << imag_link << filePath;
    // 保存图片到文件
    if (image.save(filePath)) {
        QPixmap pixmap(filePath);
        if (!pixmap.isNull()) {
            // 调整图像大小以适应窗口
            pixmap = pixmap.scaled(lab_preivew->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
            // 在标签中显示图像
            lab_preivew->setPixmap(pixmap);
        }
        ui->ui_box_page->setCurrentIndex(4); //跳转到预览的图像
        return imag_link;
    } else {
        //qDebug() << "保存图片失败。";
        return clipboard->text();
    }
}


void team_mdle::on_ui_tree_body_customContextMenuRequested(const QPoint &pos)
{
    //qDebug() << pos;
    QMenu menu;
    // 获取点击位置
    QPoint globalPos = ui->ui_tree_body->mapToGlobal(pos);
    //添加action
    QAction *action1 = new QAction(QStringLiteral("复制起点"));

    menu.addAction(action1);

    connect(action1,&QAction::triggered,this,&team_mdle::copy_body_node);

    menu.exec(globalPos);
}
void team_mdle::copy_body_node()
{
    //读取当前的标题
    QString s_node;
    if(body_index.isValid())
    {
        s_node = tocModelBody->data(body_index,Qt::DisplayRole).toString();
    }
    QRegularExpression headingRegex("^(.*)\\{#(.*?)\\}", QRegularExpression::MultilineOption);
    QRegularExpressionMatchIterator matchIterator = headingRegex.globalMatch(s_node);
    QString s_sign_contxt;
    QString s_sign_target;
    qDebug() << s_node << "^(.*)\\{#(.*?)\\}";
    if(matchIterator.hasNext()) //
    {
        //更新所有的节点
        //qDebug() << matchIterator.next().captured(0) << matchIterator.next().captured(2) << matchIterator.next().captured(3);
        QRegularExpressionMatch match = matchIterator.next();
        s_sign_contxt  = match.captured(1);
        s_sign_target  = match.captured(2);

    }
    QString link;
    link =  "| ["+ s_sign_target + "](#{" + s_sign_target + "})" + "| " + s_sign_contxt;
    //复制到剪切板
    QClipboard *clipboard = QApplication::clipboard();
    // 将文本复制到剪贴板
    clipboard->setText(link);
    //qDebug() << "result" << s_node << "index" << anysis_index;
}

void team_mdle::on_ui_tree_body_clicked(const QModelIndex &index)
{
    body_index = index;
}

